#pragma once
#include <windows.h>
#include <Xinput.h>
#include <vector>
#define UBIT16_CVT(val) ((((USHORT)val & 0xff00)>> 8) | (((USHORT)val & 0x00ff) << 8))
#define UBIT32_CVT(val) ((((UINT)(val) & 0xff000000) >> 24) | \
						(((UINT)(val) & 0x00ff0000) >> 8) | \
						(((UINT)(val) & 0x0000ff00) << 8) | \
						(((UINT)(val) & 0x000000ff) << 24))

struct _GE_BUFF_
{
	BYTE* bits = nullptr;
	UINT64 len = 0;
	UINT64 cap = 0;
	void resize(UINT64 s)
	{
		if (s > cap)
		{
			delete bits;
			bits = new BYTE[s];
			cap = s;
		}
		len = s;
	}

	~_GE_BUFF_()
	{
		delete bits;
		bits = nullptr;
		len = 0;
		cap = 0;
	}
};

enum _CODEC_ { H264, HEVC};

struct _RESOLUTION_
{
	USHORT x;
	USHORT y;
	bool operator <(const _RESOLUTION_& rhs) const
	{
		return (x != rhs.x) ? x < rhs.x : y < rhs.y;
	}
};

struct _ENC_PARAMS_
{
	UINT			version;
	INT				output_delay;
	_CODEC_			codec;
	INT				width;
	INT				height;
	INT				fps;
	INT				bit_rate;
};

enum _POINTER_FLAGS_ { UNKNOW_TYPE = 0, Monochrome = 1, Color = 2, MaskedColor = 4};

struct _CURSOR_DESC_
{
	_POINTER_FLAGS_ type;
	BOOL			hidden;
	UINT			width;
	UINT			height;
	UINT			xhotspot;
	UINT			yhotspot;
	UINT			pitch;
	UINT			buff_len;
	BYTE*			bits;

	bool operator==(_CURSOR_DESC_ const & rhs) const
	{
		if (hidden != rhs.hidden)
		{
			return false;
		}
		if (hidden == TRUE)
		{
			return true;
		}
		return memcmp(&type, &rhs.type, offsetof(_CURSOR_DESC_, bits)) == 0
			? !memcmp(bits, rhs.bits, buff_len) : false;
	}
};

struct _VIDEO_DESC_
{
	UINT	frame_idx;
	UINT	buff_size;
	BYTE*	bits;
	BYTE	pic_type;
	BYTE	codec;
	USHORT	cap_cost;
	USHORT	enc_cost;
};

struct _AUDIO_DESC_
{
	_GE_BUFF_* buff_array;
	UINT64	   array_size;
	UINT64	   capability;
	void resize(UINT64 s)
	{
		if (s > capability)
		{
			delete[] buff_array;
			buff_array = new _GE_BUFF_[s];
			capability = s;
 		}
		array_size = s;
	}

	void clear()
	{
		delete[] buff_array;
		array_size = 0;
		capability = 0;
	}
};

////////////////////////////////////////////////////////////////////////////////
enum _INPUT_TYPE_ { mouse, keyboard, gamepad, unicode, mic};

struct _UNICODE_DESC_
{
	USHORT code;
};

struct _MOUSE_INPUT_DESC_
{
	BYTE button;
	CHAR wheel;
	FLOAT x_abs;
	FLOAT y_abs;
	INT	 x_rel;
	INT  y_rel;
	BYTE state;
};

struct _KEYBOARD_INPUT_DESC_
{
	BYTE* buff;
	UINT len;
	BOOL reset;
};

struct _GAMEPAD_INPUT_DESC_
{
	BYTE			idx;
	XINPUT_GAMEPAD	x;
};

struct _MIC_INPUT_DESC_
{
	UINT	sample;
	UINT	frame;
	UINT	len;
	BYTE	channel;
	BYTE	block;
	BYTE*	buff;
};

struct _INPUT_DESC_
{
	_INPUT_TYPE_ type;
	union
	{
		_MOUSE_INPUT_DESC_		ms;
		_KEYBOARD_INPUT_DESC_	kb;
		_UNICODE_DESC_			unicode;
		_GAMEPAD_INPUT_DESC_	gpd;
		_MIC_INPUT_DESC_		mic;
	};
};
////////////////////////////////////////////////////////////////////////////////

struct _CTL_DESC_
{
	UINT	type;
	UINT64	len;
	BYTE*	buff;
};



////////////////////////////////////////////////////////////////////////////////
enum _DATA_TYPE_ { Control, Video, Cursor, Audio, Input , Web, Speedtest};

struct _COMMON_DATA_
{
	_DATA_TYPE_			type;
	union
	{
		_VIDEO_DESC_	video;
		_CURSOR_DESC_	cursor;
		_AUDIO_DESC_	audio;
		_INPUT_DESC_	input;
		_CTL_DESC_		ctl;
	};
};
////////////////////////////////////////////////////////////////////////////////


template
<
	template<typename TY, typename Alloc = std::allocator<TY>>
	class _Container = std::vector 
>
struct _STREAM_DATA_
{
	BOOL							update = FALSE;
	_Container<std::vector<BYTE>>	data_vec;
};


#pragma pack(1)
struct _NEW_RTP_
{
	USHORT data_frame_no;
	USHORT pack_no;
	USHORT pack_count;
	BYTE	ctl;
	BYTE	type;
	UINT64 rtp_no;
};

struct _MSG_FROM_WEB_
{
	USHORT opt;
	BYTE type;
	struct
	{
		UINT	op;
		UINT	time;
	};
	struct
	{
		UINT	len;
		BYTE*	bits;
	};
};

#pragma pack()